(function() {
    var _toString = Object.prototype.toString;
    var RAND_MAX = 32767; // 2^16 -1，在二進位是 15 個 1
    
    var _date = new Date();
    
    var randSeed = (_date.getTime() - _date.getSeconds()) * RAND_MAX / _date.getMilliseconds();
    var n1 = 214013;
    var n2 = 2531011;
    var count = 0;
    
    var srand = function(seed) {
        if (seed) {
            randSeed = seed;
        } else {
            _date = new Date();
            randSeed = (randSeed + _date.getTime() * _date.getMinutes()) >>> 3;
            randSeed = (randSeed - (_date.getDate() * _date.getSeconds())) >>> 3;
            randSeed = (randSeed + (_date.getMilliseconds() / _date.getMinutes()));
            randSeed = (randSeed * (count + RAND_MAX)) >>> 2;
            randSeed += _date.getMilliseconds();
            if (count == RAND_MAX) {
                count = 0;
            }
        }
    };

    // int 版
    var rand_i = function() {
        if (!(count % 200)) {
            srand();
        }
        count++;

        randSeed = randSeed * n1 + n2;
        randSeed = randSeed >>> 17; // 32-15 = 17
        return randSeed;
    };

    // float 版
    var rand_f = function() {
        if (!(count % 200)) {
            srand();
        }
        count++;

        randSeed = randSeed * n1 + n2;
        randSeed = randSeed >>> 12;
        return (randSeed / Math.pow(2, 20));
    };

    var rand_mm = function(_min, _max, _present) {
        var _present = (_toString.call(_present) == '[object Array]') ? (_present) : (null);
        if (!(count % 200)) {
            srand();
            count = 0;
        }
        count++;

        var _min = Math.min(_min, _max);
        var _max = Math.max(_min, _max);
        // 含 _max 的話改成 (_max-_min+1)
        var _seed = rand_f();
        var _num = _seed * (_max - _min) + _min;
        if (_present) {
            _present.push({'seed': _seed, 'rnd': _num});
        }
        return _num;
    };

    var _PI = Math.PI;
    var rand_Gaussian = function(_present, a, b, c) {
        var _present = (_toString.call(_present) == '[object Array]') ? (_present) : (null);
        if (!(count % 200)) {
            srand();
            count = 0;
        }
        count++;

        // f(x) = a*exp(-(x-b)**/2(c**))
        var a = (!!a) ? (a) : (1 / Math.sqrt(2 * _PI));
        var b = (!!b) ? (b) : (0);
        var c = (!!c) ? (c) : (1);

        var _max = 4 * Math.abs(c);
        var _min = -_max;
        var _num = rand_mm(_min, _max);
        var _seed = _num;
        _num = -(((_num - b) * (_num - b)) / 2 * c * c);
        _num = a * Math.exp(_num);
        if (_present) {
            _present.push({'seed': _seed, 'rnd': _num});
        }
        return _num;
    };

    var rand_Cauchy = function() {
        var _present = (_toString.call(_present) == '[object Array]') ? (_present) : (null);
        if (!(count % 200)) {
            srand();
        }
        count++;
    };

    var rand_cos = function(_present, scaleLv, limit, dtheta) {
        var _present = (_toString.call(_present) == '[object Array]') ? (_present) : (null);
        if (!(count % 200)) {
            srand();
        }
        count++;

        var scaleLv = (!!scaleLv) ? (scaleLv) : (1);
        var limit = (!!limit) ? (limit) : (1);
        var dtheta = (!!dtheta) ? (dtheta) : (0);
        var _max = _PI * scaleLv + dtheta;
        var _min = dtheta;
        var _num = rand_mm(_min, _max);
        var _seed = _num;
        _num = limit * Math.cos(_seed);
        if (_present) {
            _present.push({'seed': _seed, 'rnd': _num});
        }
        return _num;
    };

    var rand_boxmuller = function(_present, mode) {
        var _present = (_toString.call(_present) == '[object Array]') ? (_present) : (null);
        var mode = (!!mode) ? (mode) : ('x');
        var p = rand_f();
        var R = Math.sqrt((-2 * Math.log(p)));

        var t = rand_f();
        var theta = 2 * _PI * t;

        var x = R * Math.cos(theta);
        var y = R * Math.sin(theta);

        //// x, y平均值0, 標準差1，可以映設到...下式：
        //// X = m + (Z * sd), 平均值m, 標準差sd
        //var _num = 10 + (x * 1);

        if (_present) {
            if (mode == 'x') {
                _present.push({'seed': p, 'rnd': x});
            } else {
                _present.push({'seed': p, 'rnd': y});
            }
        }
        //console.log('seed：' + theta);
        //console.log('rnd：' + x);

        return (mode == 'x') ? (x) : (y);
    };

    var _rnd = {
        'srand': srand,
        'rand_i': rand_i,
        'rand_f': rand_f,
        'rand_mm': rand_mm,
        'rand_g': rand_Gaussian,
        'rand_cos': rand_cos,
        'rand_boxmuller': rand_boxmuller
    };

    window.RND = _rnd;
})();
(function() {
    var RAND_MAX = 32767; // 2^16 -1，在二進位是 15 個 1
    var _PI = Math.PI;
    var radius = 3;
    var deltaDist = 3;
    var scaleDist = 10;
    var canvas;
    var ctx;

    var _init = function() {
        canvas = document.getElementById('rnd_demo');
        canvas.width = 2 * canvas.clientWidth + scaleDist;
        canvas.height = 2 * canvas.clientHeight + scaleDist;
	    if (!canvas || !canvas.getContext) {
	    	return;
	    }
	    ctx = canvas.getContext('2d');
        ctx.lineWidth = 3;
    };

    var _canvasLear = function() {
		ctx.clearRect(0, 0, canvas.width, canvas.height);

        ctx.beginPath();
            ctx.moveTo(deltaDist, 0);
            ctx.lineTo(deltaDist, (canvas.height - deltaDist));
            ctx.moveTo(deltaDist, (canvas.height - deltaDist));
            ctx.lineTo(canvas.width, (canvas.height - deltaDist));
        ctx.closePath();
        ctx.stroke();
    };
    var rand_i = function(pts) {
        _canvasLear();

        var _ptsLen = pts[0].length;
        var _w = canvas.width - scaleDist;
        var _h = canvas.height - scaleDist;
        for (var i = 0; i < _ptsLen; i++) {
            var _xi = (pts[0][i] / RAND_MAX) * _w + deltaDist;
            var _yi = ((RAND_MAX - pts[1][i]) / RAND_MAX) * _h - deltaDist;
            ctx.beginPath();
                ctx.arc(_xi, _yi, radius, 0, 2 * _PI, false);
            ctx.closePath();
            ctx.fill();
        }
    };

    var rand_f = function(pts) {
        _canvasLear();

        var _ptsLen = pts[0].length;
        var _w = canvas.width - scaleDist;
        var _h = canvas.height - scaleDist;
        for (var i = 0; i < _ptsLen; i++) {
            var _xi = (pts[0][i]) * _w + deltaDist;
            var _yi = (1 - pts[1][i]) * _h - deltaDist;
            ctx.beginPath();
                ctx.arc(_xi, _yi, radius, 0, 2 * _PI, false);
            ctx.closePath();
            ctx.fill();
        }
    };

    var rand_mm = function(pts, min, max) {
        _canvasLear();

        var _ptsLen = pts.length;
        var _range = Math.abs(max - min);
        var _w = canvas.width - scaleDist;
        var _h = canvas.height - scaleDist;
        for (var i = 0; i < _ptsLen; i++) {
            var _xi = (pts[i].seed) * _w + deltaDist;
            var _yi = ((_range - pts[i].rnd) / _range) * _h - deltaDist;
            ctx.beginPath();
                ctx.arc(_xi, _yi, radius, 0, 2 * _PI, false);
            ctx.closePath();
            ctx.fill();
        };
    };

    var rand_g = function(pts, a, b, c) {
        _canvasLear();

        var a = (!!a) ? (a) : (1 / Math.sqrt(2 * _PI));
        var b = (!!b) ? (b) : (0);
        var c = (!!c) ? (c) : (1);

        var _max = 4 * Math.abs(c);
        var _min = -_max;
        var _range = Math.abs(_max - _min);
        var _ptsLen = pts.length;
        var _w = canvas.width - scaleDist;
        var _h = canvas.height - scaleDist;
        for (var i = 0; i < _ptsLen; i++) {
            var _xi = ((pts[i].seed - _min) / _range) * _w + deltaDist;
            var _yi = ((1.3 * a - pts[i].rnd) / (1.3 * a)) * _h - deltaDist;
            ctx.beginPath();
                ctx.arc(_xi, _yi, radius, 0, 2 * _PI, false);
            ctx.closePath();
            ctx.fill();
        }
    };

    var rand_cos = function(pts, scaleLv, limit, dtheta) {
        _canvasLear();

        var scaleLv = (!!scaleLv) ? (scaleLv) : (1);
        var limit = (!!limit) ? (limit) : (1);
        var dtheta = (!!dtheta) ? (dtheta) : (0);
        var _max = scaleLv * _PI + dtheta;
        var _min = dtheta;
        var _range = Math.abs(_max - _min);
        var _ptsLen = pts.length;
        var _w = canvas.width - scaleDist;
        var _h = canvas.height - scaleDist;
        for (var i = 0; i < _ptsLen; i++) {
            var _xi = ((pts[i].seed - _min) / _range) * _w + deltaDist;
            var _yi = ((1.3 * limit - pts[i].rnd) / (2.6 * limit)) * _h - deltaDist;
            ctx.beginPath();
                ctx.arc(_xi, _yi, radius, 0, 2 * _PI, false);
            ctx.closePath();
            ctx.fill();
        }
    };

    var rand_boxmuller = function(pts) {
        _canvasLear();

        var _max =  3;
        var _min = -3;
        var _range = Math.abs(_max - _min);
        var _ptsLen = pts.length;
        var _w = canvas.width - scaleDist;
        var _h = canvas.height - scaleDist;
        var r = 1.5;
        for (var i = 0; i < _ptsLen; i++) {
            var _xi = ((pts[i].rnd - _min) / _range) * _w + deltaDist;
            var _yi = ((r - pts[i].seed) / (r)) * _h - deltaDist;
            ctx.beginPath();
                ctx.arc(_xi, _yi, radius, 0, 2 * _PI, false);
            ctx.closePath();
            ctx.fill();
        }
    };

    var _present = {
        '_init': _init,
        'rand_i': rand_i,
        'rand_f': rand_f,
        'rand_mm': rand_mm,
        'rand_g': rand_g,
        'rand_cos': rand_cos,
        'rand_boxmuller': rand_boxmuller
    };
    window.PRESENT = _present;
})();
